package pers.ree.demo.lambda;

import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class MyFunctionalDemo {

    public static void main(String[] args) {
        /**
         *  自定义的函数式接口的用法 begin
         **/
        // 这里的Lambda表达式创建了一个MyFunctionalInterface接口的匿名实现类的实例
        MyFunctionalInterface myFunctional = () -> System.out.println("my functional begin...");
        myFunctional.doWork();

        // 传入一个MyFunctionalInterface接口的匿名实现类的实例作为参数
        performAction(() -> System.out.println("Action performed with Lambda"));
        /** 自定义的函数式接口的用法 end */


        /**
         * 几种常见的jdk自带的函数式接口的用法 begin
         * Runnable, Predicate, Consumer, Supplier, Function
         **/
        // Runnable适用于无参方法，无论是否有返回值
        Runnable runnable = MyClass::staticPrint;
        runnable.run();


        // Predicate<T>只能用于一个参数，且返回值为boolean类型的方法，T为参数类型
        Predicate<Integer> predicate = MyClass::staticAddPositive;
        boolean predicateTestResult = predicate.test(2);
        System.out.println("predicateTestResult="+predicateTestResult);

        Predicate<String> stringLengthPredicate = s -> s.length() > 5;
        boolean stringLengthPredicateResult = stringLengthPredicate.test("test123");
        System.out.println("stringLengthPredicateResult="+stringLengthPredicateResult);


        // Consumer<T>用于只有一个参数且没有返回值的方法，T为参数类型
        // 使用场景：消费、处理传入的参数
        Consumer<Integer> consumer = MyClass::staticSet;
        consumer.accept(666);

        // Supplier<T>用于无参数且有一个返回值的方法，T为返回值类型
        // Supplier意为生产者，用法刚好与Consumer相反
        Supplier<Integer> supplier = MyClass::staticGet;
        int supplierResult = supplier.get();
        System.out.println("supplierResult="+supplierResult);


        // Function<T,R>用于一个参数且有返回值的方法，T为参数类型，R为返回值类型
        // 主要作用：类型转换，将参数类型转换为返回值类型
        // 典型示例：Iterable接口的forEach
        Function<Integer, Boolean> function = MyClass::staticAddPositive;
        boolean functionResult = function.apply(999);
        System.out.println("functionResult="+functionResult);
        /** 几种常见的jdk自带的函数式接口的用法 end */


        /**
         * 构造方法的引用的用法 begin
         **/
        // 数组::new
        testArrayNew();


        // 类名::new
        testClassNew();
        /** 构造方法的引用的用法 end */
    }

    /**
     * 自定义的函数式接口作为参数
     * @param action
     */
    public static void performAction(MyFunctionalInterface action) {
        action.doWork();
    }

    /**
     * 类名::new
     * 类名::new是类构造方法的引用
     */
    public static void testClassNew() {
        // 无参构造方法
        Supplier<MyClass> paramLessConstructorRef = MyClass::new;
        MyClass paramLessMyClass = paramLessConstructorRef.get();
        System.out.println("paramLessMyClass name="+paramLessMyClass.getName());

        // 一个参数的构造方法
        Function<String, MyClass> paramOneConstructorRef = MyClass::new;
        MyClass paramOneMyClass = paramOneConstructorRef.apply("zys");
        System.out.println("paramOneMyClass name="+paramOneMyClass.getName());
    }

    /**
     * 数组::new的用法
     * 数组::new是数组构造方法的引用
     */
    public static void testArrayNew() {
        // 直接使用构造函数引用创建数组
        Function<Integer, String[]> arrayRef = String[]::new;
        String[] strArray = arrayRef.apply(20);
        System.out.println("strArray length="+strArray.length);

        // 在集合操作中使用
        List<String> strList = Arrays.asList("Hello", "World");
        String[] strArrayFromList = strList.stream().toArray(String[]::new);
        System.out.println("strArrayFromList length="+strArrayFromList.length);

        // 作为参数传递给其他方法
        createAndProcessArray(String[]::new, 5);

        // 在stream流中使用
        String[] strArr = {"1", "2", "3"};
        Stream<String> strStream = Arrays.stream(strArr);
        // toArray的参数类型为IntFunction<A[]>
        String[] strArrFromStream = strStream.toArray(String[]::new);
        System.out.println("strArrFromStream length="+strArrFromStream.length+", strArrFromStream[0]="+strArrFromStream[0]);
    }

    /**
     * 数组的引用作为参数
     * @param creator
     * @param size
     * @param <T>
     */
    public static <T> void createAndProcessArray(Function<Integer, T[]> creator, int size) {
        T[] array = creator.apply(size);
        // 处理数组
        System.out.println("createAndProcessArray array length="+array.length);
    }
}
